<!doctype html>
<html>
	<head>
		<meta charset='UTF-8'>
		<meta name='viewport' content='width=device-width initial-scale=1'>
		<title></title>
		<link rel="stylesheet" href="css/font.css">
		<link rel="stylesheet" type="text/css" href="../css/wenzhang.css" />
		<link rel="stylesheet" type="text/css" href="../css/index.css"/>
		<style>
			 #goToTop {
      position: fixed;
      bottom: 20px;
      right: 10%;
   }
  #goToTop a {
     background: none repeat scroll 0 0 #336699;
     border: 1px solid #CCCCCC;
     border-radius: 3px;
     -webkit-border-radius: 3px;
     color: #FF9966;
     font-size: 14px;
     padding: 5px;
     text-decoration: none;
     text-shadow: 0 1px 0 #999;
     -webkit-text-shadow: 0 1px 0 #999;            
     }
		</style>
		<script src="../js/jquery-2.1.4.min.js"></script>
		<script type="text/javascript">
			$(document).ready(function(){
				$("#goToTop").hide()//隐藏go to top按钮
				$(function(){
					$(window).scroll(function(){
						if($(this).scrollTop()>1){//当window的scrolltop距离大于1时，go to top按钮淡出，反之淡入
							$("#goToTop").fadeIn();
						} else {
							$("#goToTop").fadeOut();
						}
					});
				});
			 
		
				// 给go to top按钮一个点击事件
				$("#goToTop a").click(function(){
					$("html,body").animate({scrollTop:0},800);//点击go to top按钮时，以800的速度回到顶部，这里的800可以根据你的需求修改
					return false;
				});
			});
		</script>
	</head>
	<body>
		<div class="daohang">
		
			<div class="right">
				<ul class="daohang_ul">
					<li><a href="../index.html">首页</a></li>
					<li><a href="./wz00.html">设计要求</a></li>
					<li><a href="../gunyvwo.html">关于我</a></li>
					<li><a href="../xiangce.html">我的相册</a></li>
					<li><a href="../shopin1.html">喜欢的视频</a></li>
					<li><a href="../register.html">登录/注册</a></li>
				</ul>
			</div>
		</div>
		<div id='write' class=''>
			<h1><a name="接口幂等性" class="md-header-anchor"></a><span>接口幂等性</span></h1>
			<blockquote>
				<p><span>作者：xiaozhi 发布于 2020-05-08</span></p>
			</blockquote>
			<pre lang="" class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false"><div class="CodeMirror cm-s-inner CodeMirror-wrap" lang=""><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 8px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><span><span>​</span>x</span></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">摘要：对于现在的分布式系统，一套系统中包含多个子服务，在一个业务流程中，往往存在多个服务互相调用的情景，而服务调用多数是RPC或者RESTFul，而由于网络的波动或者其他异常情况，可能会存在未及时返回处理结果的情况，这个时候用户多次点击调用，是否能够产生相同的结果呢？这就是接口幂等性需要考虑的问题。</span></pre>
		</div>
		</div>
		</div>
		</div>
		</div>
		</div>
		<div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 69px;"></div>
		<div class="CodeMirror-gutters" style="display: none; height: 69px;"></div>
		</div>
		</div>
		</pre>
		<h3><a name="幂等性" class="md-header-anchor"></a><span>幂等性</span></h3>
		<p><span>幂等性就是用于的统一操作发起的一次或者多次请求的结果是一致的，不会因为多次点击产生其他结果。</span></p>
		<p><span>在CRUD的四个步骤中，尤其是在update，insert的时候需要注意保证接口的幂等性。</span></p>
		<h2><a name="insert操作" class="md-header-anchor"></a><span>Insert操作</span></h2>
		<p><span>增加在重复提交的时候会出现幂等性的问题。比如在支付的时候，用户在第一次点提交的时候，已经扣完款了，但是迟迟没有结果，于是点了第二次，这个时候如果没有做幂等性的限制，那么会对同一笔订单进行多次扣款。</span></p>
		<h2><a name="select操作" class="md-header-anchor"></a><span>Select操作</span></h2>
		<p><span>对于查询操作，查询的结果在数据不变的情况下，一次查询和多次查询的结果是一样的。</span><strong><span>Select操作是天然的幂等性</span></strong></p>
		<h2><a name="delete操作" class="md-header-anchor"></a><span>Delete操作</span></h2>
		<p><span>对于删除操作，删除一次和删除多次都是为了将数据删除。但是删除的时候可能存在结果不同，比如删除不存在的数据返回为0，删除存在的数据返回的是受影响的行数。如果不考虑删除结果对后续操作的影响，那么可以说删除操作是幂等性的。</span></p>
		<h2><a name="update操作" class="md-header-anchor"></a><span>Update操作</span></h2>
		<p><span>修改在大多数场景下都是幂等性的。</span></p>
		<p><span>比如：</span></p>
		<p><span>将表中id为1的数据的A字段设置为1，这个操作不管执行多少次都是幂等性的。</span></p>
		<p><span>但是在涉及到增量修改的时候，就需要格外的手段来保证幂等性。</span></p>
		<p><span>比如：</span></p>
		<p><span>将表中id为1的数据的A字段增加1，这个操作就不是幂等性的。</span></p>
		<h1><a name="如何设计接口做到幂等" class="md-header-anchor"></a><span>如何设计接口做到幂等</span></h1>
		<p><span>常见的有两种方案：</span></p>
		<p><span>A：通过代码逻辑判断</span></p>
		<p><span>B：使用Token机制实现</span></p>
		<h2><a name="通过代码逻辑实现" class="md-header-anchor"></a><span>通过代码逻辑实现</span></h2>
		<p><span>通过代码逻辑判断实现接口的幂等性，只能针对一些满足判断的逻辑实现，具有一定的局限性。</span></p>
		<p><span>比如：在新增用户的时候，可以先去查询数据库中是否有重复的记录，如果已经有相同数据的时候，就直接返回该数据，忽略新增操作。</span></p>
		<p><span>随着分布式系统及微服务的普及，因为网络原因而导致调用系统未能获取到确切的结果从而导致重试，这就需要被调用系统具有幂等性。</span></p>
		<h2><a name="使用token机制实现接口幂等性" class="md-header-anchor"></a><span>使用token机制实现接口幂等性</span></h2>
		<p><span>这是一个通用性强的实现方法。</span></p>
		<p><span>token机制实现步骤:</span></p>
		<ol>
			<li><span>生成全局唯一的token,token放到redis或jvm内存,token会在页面跳转时获取.存放到pageScope中,支付请求提交先获取token。</span></li>
			<li><span>提交后后台校验token，执行提交逻辑,提交成功同时删除token，生成新的token更新redis ,这样当第一次提交后token更新了,页面再次提交携带的token是已删除的token后台验证会失败不让提交。</span></li>
		</ol>
		<p><span>token特点：</span></p>
		<p><span>要申请，一次有效性，可以限流</span></p>
		<p><span>注意：</span></p>
		<p><span>redis要用删除操作来判断token，删除成功代表token校验通过，如果用select+delete来校验token，存在并发问题，不建议使用。</span></p>
		</div>
		<div id="goToTop"><a href="#">点我回到页面顶部</a></div>
	</body>
</html>
